from django.shortcuts import render
from django.views import View
from django import http
import re
import json
from django.shortcuts import render, redirect,reverse
from users.models import User
from django.contrib.auth import login, logout, authenticate
from django_redis import get_redis_connection
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
# from celery_tasks.tasks.mail import send_mail_celery
from utils.response_code import RET
from utils.mail_token import encode_signature_mail_url, decode_signature_mail_url
from django.conf import settings
from goods.models import SKU
from users.models import User



# Create your views here.

class RegisterView(View):
    def get(self,request):
        return render(request,'register_vue.html')

        # 用户注册接口

    def post(self, request):
        # 1, 初始化数据
        data = request.POST
        user_name = data.get('user_name')
        pwd = data.get('pwd')
        cpwd = data.get('cpwd')
        phone = data.get('phone')
        msg_code = data.get('msg_code')   #前端传过来的短信验证码
        allow = data.get('allow')

        # 1,1 判断数据是否都有
        if not all([user_name, pwd, cpwd, phone, msg_code, allow]):
            return http.HttpResponseForbidden('参数不全')

        # 1,2 校验用户名
        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', user_name):
            return http.HttpResponseForbidden('用户名格式有误')

        # 1,3 校验密码
        if not re.match(r'^[0-9A-Za-z]{8,20}$', pwd):
            return http.HttpResponseForbidden('密码格式有误')

        # 1,4 两遍密码是否相同
        if pwd != cpwd:
            return http.HttpResponseForbidden('两遍密码不同')

        # 1,5 校验手机号
        if not re.match(r'^1[3-9]\d{9}$', phone):
            return http.HttpResponseForbidden('手机号格式不正确')

        #1,6 校验短信验证码
        redis_conn = get_redis_connection('verify_code')
        redis_sms_code = redis_conn.get('sms_%s' % phone).decode()
        if msg_code != redis_sms_code:
            return http.HttpResponseForbidden('短信验证码错误')

        if allow != 'on':
            return http.HttpResponseForbidden('请同意用户协议')

        # 2, 处理业务
        # 2,1 创建用户
        try:
            user = User.objects.create_user(username=user_name, password=pwd, mobile=phone)
        except Exception as e:
            # return render(request, 'register_vue.html', {'register_errmsg': '注册失败'})
            print(e)
            return http.HttpResponseForbidden('注册失败')


        # 把user指代的用户进行了登录操作
        # login(request, user)
        # # 3, 返回响应
        # # url = reverse('')
        # # return redirect('http://www.jd.com')
        # return redirect(reverse('contents:index'))
        login(request, user)
        response = redirect('/')
        response.set_cookie('username', user.username)  # 设置要存的cookie名字备注和用户名
        # return render(request, 'index.html')
        return response

class UsernameCountView(View):
    def get(self, request, username):
        # 1, 初始化数据
        pass

        # 2, 处理业务逻辑
        count = User.objects.filter(username=username).count()

        # 3, 返回响应
        res = {
            'code': 0,
            'errmsg': 'success',
            'count': count
        }

        return http.JsonResponse(res)

class MobileCountView(View):
    """判断手机号是否重复注册"""

    def get(self, request, mobile):
        """
        :param request: 请求对象
        :param mobile: 手机号
        :return: JSON
        """
        count = User.objects.filter(mobile=mobile).count()
        return http.JsonResponse({'code': 0, 'errmsg': 'OK', 'count': count})

class LoginView(View):
    def get(self,request):
        return render(request,'login.html')

    def post(self,request):
        #1.初始化数据，获取数据，校验数据
        username=request.POST.get('username')
        password=request.POST.get('pwd')
        remembered=request.POST.get('remembered')

        if not all([username, password]):
            return http.HttpResponseForbidden('参数不全')

        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return http.HttpResponseForbidden('用户名格式错误')

        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return http.HttpResponseForbidden('密码格式错误')

    #方法一验证用户是否存在
        #2.处理业务逻辑
        # try:
        #     user=User.objects.get(username=username)
        # except Exception as e:
            #pass
        #     return http.HttpResponseForbidden('用户名不存在')
            # try:
            #     user=User.objects.get(mobile=username)
        # if not user.check_password(password):
        #     return http.HttpResponseForbidden('密码不正确')
    # 方法二验证用户是否存在(django系统提供的)
        user = authenticate(username=username, password=password)
        if not user:
            return http.HttpResponseForbidden('用户名密码错误!')

        login(request,user)
        response=redirect('/')
        response.set_cookie('username',user.username)  #设置要存的cookie名字备注和用户名
        # return render(request, 'index.html')
        return response


        # 实现状态保持
        # login(request, user)
        # # 设置状态保持的周期
        # if remembered != 'on':
        #     # 没有记住用户：浏览器会话结束就过期
        #     request.session.set_expiry(0)
        # else:
        #     # 记住用户：None表示两周后过期
        #     request.session.set_expiry(None)





        pass

class LogoutView(View):
    def get(self,request):
        #1.初始化数据


        #2.处理业务数据
        logout(request)

        #3返回数据
        response=redirect('/')
        response.delete_cookie('username')

        return response

@method_decorator(login_required,name='dispatch')
class LoginRequiedView(View):
    # @method_decorator(login_required, name='dispatch')
    # def dispatch(self, request, *args, **kwargs):
    #     return super().dispatch(request, *args, **kwargs)
    pass

class UserCenterView(LoginRequiedView):
    def get(self,request):
        #检测用户是否在登陆状态，如果不是跳到登陆页面

        #使用user认证
        # if request.user.is_authenticated():
        #     pass
        # else:
        #     return redirect('/login/')
        #
        context={
            'username':request.user.username,
            'mobile':request.user.mobile,
            'email':request.user.email,
            'email_active':request.user.email_active

        }


        return render(request,'user_center_info.html',
                      context=context)

class EmailView(LoginRequiedView):
    def put(self,request):
        #1.初始化数据
        data=json.loads(request.body.decode())
        email=data.get('email')
        #1.1校验邮箱
        if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
            return http.JsonResponse({'code': RET.PARAMERR, 'errmsg':'邮箱格式有误'})

        #2.处理业务逻辑
        user=request.user
        user.email=email
        user.save()

        from celery_tasks.tasks.mail import send_mail_celery
        token_str=json.dumps({
            'user':user.username
        })
        send_mail_celery.delay('验证邮件',token_str,[user.email])


        #3.返回响应
        res={
            'code':RET.OK,
            'errmsg':'设置成功'
        }
        return http.JsonResponse(res)     #####超级多问题

class AddressView(LoginRequiedView):
    def get(self, request):
        # 1,初始化数据
        user = request.user

        # 2,处理业务逻辑
        # 取用户的地址列表
        addresses = user.addresses.filter(is_deleted=False)
        addresses_list = []
        for address in addresses:
            address_data = {
                'id': address.id,  # 前端需要id来判断是否和默认地址id相同
                'title': address.title,
                'receiver': address.receiver,
                'province': address.province.name,  # <Area: 山西省>
                'province_id': address.province.id,  # <Area: 山西省>
                'city': address.city.name,
                'city_id': address.city.id,
                'district': address.district.name,
                'district_id': address.district.id,
                'place': address.place,
                'mobile': address.mobile,
                'tel': address.tel,
                'email': address.email,
            }
            addresses_list.append(address_data)

        # 3,返回响应

        context = {
            'addresses': json.dumps(addresses_list),
            'default_address_id': user.default_address_id
        }
        return render(request, 'user_center_site.html', context=context)


class CreateAddressView(LoginRequiedView):
    def post(self, request):
        # 1,初始化数据
        data = json.loads(request.body.decode())
        """
        city_id: 440100
        district_id: 440106
        email: ""
        mobile: "13312341234"
        place: "珠吉路58号"
        province_id: 440000
        receiver: "张三"
        tel: ""
        title: "张三"
        """
        city_id = data.get('city_id')
        district_id = data.get('district_id')
        email = data.get('email')
        mobile = data.get('mobile')
        place = data.get('place')
        province_id = data.get('province_id')
        receiver = data.get('receiver')
        tel = data.get('tel')
        title = data.get('title')

        # 校验参数
        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return http.HttpResponseForbidden('缺少必传参数')
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseForbidden('参数mobile有误')
        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return http.HttpResponseForbidden('参数tel有误')
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return http.HttpResponseForbidden('参数email有误')

        # 2,处理业务逻辑
        try:
            address = Address.objects.create(
                user=request.user,
                title=title,
                receiver=receiver,
                province_id=province_id,
                city_id=city_id,
                district=Area.objects.get(id=district_id),
                # district_id = district_id
                place=place,
                mobile=mobile,
                tel=tel,
                email=email,
            )
            # address.save()  # ?
        except Exception as e:
            return http.JsonResponse({'code': '', 'errmsg': '地址创建失败'})

        # 3,返回响应
        address_data = {
            'id': address.id,  # 前端需要id来判断是否和默认地址id相同
            'title': address.title,
            'receiver': address.receiver,
            'province': address.province.name,  # <Area: 山西省>
            'province_id': address.province.id,  # <Area: 山西省>
            'city': address.city.name,
            'city_id': address.city.id,
            'district': address.district.name,
            'district_id': address.district.id,
            'place': address.place,
            'mobile': address.mobile,
            'tel': address.tel,
            'email': address.email,
        }
        res = {
            'code': RET.OK,
            'errmsg': '地址创建成功',
            'address': address_data
        }
        return http.JsonResponse(res)


class UpdateDestroyAddressView(LoginRequiedView):
    def put(self, request, address_id):
        # 更新地址信息
        # 1,初始化数据
        data = json.loads(request.body.decode())
        receiver = data.get('receiver')
        province_id = data.get('province_id')
        city_id = data.get('city_id')
        district_id = data.get('district_id')
        place = data.get('place')
        mobile = data.get('mobile')
        tel = data.get('tel')
        email = data.get('email')
        # 校验数据
        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return http.HttpResponseForbidden('缺少必传参数')
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseForbidden('参数mobile有误')
        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return http.HttpResponseForbidden('参数tel有误')
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return http.HttpResponseForbidden('参数email有误')

        # 2,处理业务逻辑
        try:
            Address.objects.filter(id=address_id).update(
                receiver=receiver,
                province_id=province_id,
                city_id=city_id,
                district_id=district_id,
                place=place,
                mobile=mobile,
                tel=tel,
                email=email
            )
        except Exception as e:
            return http.JsonResponse({'code': RET.DBERR, 'errmsg': '数据更新失败'})

        try:
            address = Address.objects.get(id=address_id)
        except Exception as e:
            return http.JsonResponse({'code': RET.DBERR, 'errmsg': '数据读取失败'})

        # 3,返回响应
        address_data = {
            'id': address.id,  # 前端需要id来判断是否和默认地址id相同
            'title': address.title,
            'receiver': address.receiver,
            'province': address.province.name,  # <Area: 山西省>
            'province_id': address.province.id,  # <Area: 山西省>
            'city': address.city.name,
            'city_id': address.city.id,
            'district': address.district.name,
            'district_id': address.district.id,
            'place': address.place,
            'mobile': address.mobile,
            'tel': address.tel,
            'email': address.email,
        }

        res = {
            'code': RET.OK,
            'errmsg': '修改成功',
            'address': address_data
        }

        return http.JsonResponse(res)

        pass

    def delete(self, request, address_id):
        # 删除地址
        # 1, 初始化数据
        try:
            address = Address.objects.get(id=address_id)
        except Exception as e:
            return http.JsonResponse({'code': RET.DBERR, 'errmsg': '地址编号有误'})

        # 2, 处理业务逻辑
        address.is_deleted = True
        address.save()

        # 3, 返回响应
        res = {
            'code': RET.OK,
            'errmsg': '删除成功'
        }
        return http.JsonResponse(res)
        pass


class DefaultAddressView(LoginRequiedView):
    def put(self, request, address_id):
        # 设置默认地址
        # 1,初始化数据
        user = request.user
        try:
            address = Address.objects.get(id=address_id)
        except Exception as e:
            return http.JsonResponse({'code': RET.PARAMERR, 'errmsg': '地址编号错误'})

        # 2,处理业务逻辑
        # user.default_address = address
        user.default_address_id = address_id
        user.save()

        # 3,返回响应
        res = {
            'code': RET.OK,
            'errmsg': '默认地址更新成功'
        }
        return http.JsonResponse(res)
        pass


class UpdateTitleAddressView(LoginRequiedView):
    def put(self, request, address_id):
        # 1,初始化数据
        # 获取数据
        data = json.loads(request.body.decode())
        title = data.get('title')
        if not all([title]):
            return http.JsonResponse({'code': RET.PARAMERR, 'errmsg': '没有标题!'})
        try:
            address = Address.objects.get(id=address_id)
        except Exception as e:
            return http.JsonResponse({'code': RET.PARAMERR, 'errmsg': '地址编号错误'})
        # 2,处理业务
        address.title = title
        address.save()

        # 3,返回响应
        res = {'code': RET.OK, 'errmsg': '修改标题成功'}
        return http.JsonResponse(res)
        pass

class PasswordChangeView(LoginRequiedView):
    def get(self, request):
        return render(request, 'user_center_pass.html')

    def post(self, request):
        # 修改密码
        # 1,初始化数据
        data = request.POST
        old_pwd = data.get('old_pwd')
        new_pwd = data.get('new_pwd')
        new_cpwd = data.get('new_cpwd')

        user = request.user

        if not user.check_password(old_pwd):
            return http.HttpResponseForbidden('密码不正确')

        if not re.match(r'^[0-9A-Za-z]{8,20}$', new_pwd):
            return http.HttpResponseForbidden('密码格式不正确')

        if new_pwd != new_cpwd:
            return http.HttpResponseForbidden('两遍密码不一致')

        if old_pwd == new_pwd:
            return http.HttpResponseForbidden('新密码和旧密码不能相同')

        # 2,处理业务
        user.set_password(new_pwd)
        user.save()

        # 3,返回响应
        logout(request)
        response = redirect('/login/')
        response.delete_cookie('username')

        return response

        pass

# class UserBrowseHistrory(LoginRequiedView):
#     def post(self,request):
#         #1.初始化数据
#         user=request.user
#         data=json.loads(request.body.decode())
#         sku_id=data.get('sku_id')
#         try:
#             sku=SKU.objects.get(id=sku_id)
#         except Exception as e:
#             return http.JsonResponse({'code':RET.PARAMERR,'errmsg':'商品编号错误'})
#
#         #2.处理业务逻辑
#         #2.1保存到redis中，先获取一个redis的链接
#         redis_conn=get_redis_connection('history')
#         #2.2去重,key的名字:history_user_id
#         #lrem history_1 0 16
#         redis_conn.lrem('history_%s' %user.id,0,sku_id)
#
#         #2.3增加
#         redis_conn.lpush('history_%s' %user.id,sku_id)
#
#         #2.4截取
#         redis_conn.ltrim('history_%s' %user.id,0,4)
#
#         #3.返回响应
#         res={
#             'code':RET.OK,
#             'errmsg':'成功'
#         }
#         return http.JsonResponse(res)
#
#         pass

class UserBrowseHistory(LoginRequiedView):
    def post(self, request):
        # 保存浏览记录
        # 1, 初始化数据
        user = request.user
        data = json.loads(request.body.decode())
        sku_id = data.get('sku_id')

        try:
            sku = SKU.objects.get(id=sku_id)
        except Exception as e:
            return http.JsonResponse({'code': RET.PARAMERR, 'errmsg': '商品编号错误'})

        # 2, 处理业务逻辑
        # 2,1保存到redis中, 先获取一个redis的链接
        redis_conn = get_redis_connection('history')
        pipeline = redis_conn.pipeline()
        # 2,2 去重, key的名字: history_user_id
        # lrem history_1 0 16
        pipeline.lrem('history_%s' % user.id, 0, sku_id)
        # 2,3 增加
        pipeline.lpush('history_%s' % user.id, sku_id)
        # 2,4 截取
        pipeline.ltrim('history_%s' % user.id, 0, 4)
        pipeline.execute()

        # 3, 返回响应
        res = {
            'code': RET.OK,
            'errmsg': '成功'
        }
        return http.JsonResponse(res)

        pass

    def get(self, request):
        # 获取用户的浏览记录
        # 1, 初始化数据
        user = request.user

        # 2, 处理业务逻辑
        # 2,1 获取一个redis_conn
        redis_conn = get_redis_connection('history')
        # 2,2 从redis中取出用的浏览记录列表
        sku_id_list = redis_conn.lrange('history_%s' % user.id, 0, -1)
        # 2,3 根据sku_id 组织数据
        skus = []
        for sku_id in sku_id_list:
            sku = SKU.objects.get(id=sku_id)
            sku_data = {
                'id': sku.id,
                'default_image_url':sku.default_image_url.url,
                'name':sku.name,
                'price':sku.price
            }
            skus.append(sku_data)

        # 3, 返回响应
        res = {
            'code': RET.OK,
            'errmsg': '成功',
            'skus': skus
        }
        return http.JsonResponse(res)
        pass


















